﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WebCrawler.Crawler.Interfaces;
using System.Threading;
using WebCrawler.Graph;
using WebCrawler.Graph.Interfaces;
using System.Collections;
using GlobalInterfaces;
using System.Diagnostics;

namespace TestGUIs
{
    public partial class TreeViewForm : Form, IObserver
    {
        private Thread _tWorker;
        private ICrawler _crawler;
        private int _errorCount = 0;
        private int _logCount = 0;
        public bool DoneCrawling { get; set; }

        public TreeViewForm()
        {
            InitializeComponent();

            // For Test only 
            //txtUrl.Text = "http://localhost/SiteMapTest";
            //txtUrl.Text = "http://public.ucn.dk/fen/testsite/";
            //txtUrl.Text = "www.ucn.dk";
            txtUrl.Text = "www.k-b-n.dk";

            string url = txtUrl.Text;
            url = url.Contains("http://") ? url : "http://" + url;

            _crawler = new WebCrawler.Crawler.Crawler(url, this);
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            btnGo.Enabled = false;
            btnStop.Enabled = true;
            cbxDubplicate.Enabled = false;
            if (txtUrl.Text.Length > 0 && (btnGo.Text == "Start" || btnGo.Text == "Resume"))
            {

                if (btnGo.Text == "Resume")
                {
                    btnGo.Text = "Pause";
                    btnGo.Enabled = true;

                    // Continueing Crawler Thread
                    if (_tWorker.ThreadState.ToString().Contains("Suspended"))
                        _tWorker.Resume();
                    return;
                }

                // Very first run

                btnGo.Text = "Pause";
                _errorCount = 0;
                _logCount = 0;
                rtxtErrorLog.Clear();
                treeView1.Nodes.Clear();
                try
                {
                    string url = txtUrl.Text.ToLower();

                }
                catch (Exception ex)
                {
                    string msg = ex.Message;
                    if (_crawler.Url == "")
                        msg = "Url is missing!";
                    MessageBox.Show(msg, "Error");
                }
                btnGo.Enabled = true;
                _crawler.MAXDEPTH = (int)nudDepth.Value;
                _crawler.Dubplicate = cbxDubplicate.Checked;

                // Start traversing and follow crawler thread
                _crawler.Traversal(out _tWorker);

                Thread t = new Thread(new ThreadStart(BuildTreeView));
                t.Name = "TreeThread";
                t.IsBackground = true;
                DoneCrawling = false;

                // Building tree until thread is done.
                while (_tWorker.IsAlive) Application.DoEvents();


                if (btnGo.Text != "Start")
                {

                    t.Start();
                }
                else
                {
                    tssErrorLog.Text = "none";
                }

                if (DoneCrawling)
                {
                    DoneCrawling = false;
                    btnGo.Text = "Start";
                    cbxDubplicate.Enabled = true;
                    MessageBox.Show("Done Crawling!");
                }

            }
            else
            {
                // Pausing Crawler Thread
                if (_tWorker.IsAlive)
                    _tWorker.Suspend();
                treeView1.Nodes.Clear();
                BuildTreeView();
                btnGo.Text = "Resume";
                btnGo.Enabled = true;
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            try
            {
                // Stopping Crawler Thread
                if (_tWorker.ThreadState.ToString().Contains("Suspended"))
                    _tWorker.Resume();
                _tWorker.Abort();

                btnGo.Text = "Start";
                btnStop.Enabled = false;
                cbxDubplicate.Enabled = true;
                webBrowser1.Url = new Uri("about:blank");
                rtxtErrorLog.Clear();
                treeView1.Nodes.Clear();
                treeView1.Invalidate();
                _errorCount = 0;
            }
            catch (Exception ex)
            {
                Update("0|" + ex.Message);
            }
        }

        private void BuildTreeView()
        {
            try
            {
                // Receive the root vertex
                IList brfTree = _crawler.GraphTraverse();
                TreeNode root = new VertexNode((Vertex)brfTree[0]);

                // Make the root TreeNode
                Queue<VertexNode> q = new Queue<VertexNode>();
                q.Enqueue((VertexNode)root);
                treeView1.Nodes.Clear();
                treeView1.Invoke(new Action(() => { treeView1.Nodes.Add(root); }));

                // Build and display the full tree
                do
                {
                    VertexNode node = q.Dequeue();
                    if (node.NVertex.Edges != null)
                    {
                        // Display all new sublinks...
                        for (int i = 0; i < node.NVertex.Edges.Count; i++)
                        {
                            VertexNode leaf = new VertexNode((Vertex)node.NVertex.Edges[i].To);
                            treeView1.BeginInvoke(new Action(() =>
                            {
                                if (leaf.NVertex.Dubplicated)
                                {
                                    leaf.ForeColor = Color.Gray;
                                }
                                node.Nodes.Add((TreeNode)leaf);
                                //treeView1.Invalidate();
                                treeView1.ExpandAll();
                            }));
                            q.Enqueue(leaf);
                        }
                    }
                    Application.DoEvents();
                } while (q.Count > 0); // end while

                treeView1.Invoke(new Action(() =>
                {
                    if (treeView1.Nodes.Count > 0)
                        treeView1.Nodes[0].Expand();

                    Thread.Sleep(600);


                }));
            }
            catch { } // When form is close on paused thread
        }

        public void Update(object obj)
        {
            try
            {
                string msg = obj.ToString();
                if (msg.StartsWith("0|")) // Error
                {
                    msg = msg.Substring(2, msg.Length - 2);
                    statusStrip1.Invoke(new Action(() =>
                    { tssErrorLog.Text = _errorCount++ + " - " + msg; }));
                }
                if (msg.StartsWith("1|")) // Current node visiting
                {
                    msg = msg.Substring(2, msg.Length - 2);
                    rtxtErrorLog.Invoke(new Action(() =>
                    {
                        string fullMsg = _logCount++ + " - " + msg + "\r\n";
                        rtxtErrorLog.AppendText(fullMsg);
                        rtxtErrorLog.Focus();
                        rtxtErrorLog.SelectionStart = rtxtErrorLog.Text.Length;
                    }));
                }
                if (msg.StartsWith("2|")) // Request update in treeview
                {
                    //if (!DoneCrawling)
                    (new Thread(new ThreadStart(UpdateTreeView))).Start();
                }
                if (msg.StartsWith("3|")) // Request update in treeview
                {
                    DoneCrawling = true;
                }
            }
            catch (Exception) { }
        }

        private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            webBrowser1.Url = new Uri(e.Node.Text);
        }

        private void UpdateTreeView()
        {
            try
            {
                if (btnGo.Text != "Start" && !DoneCrawling)
                {
                    // Pause crawler thread
                    if (_tWorker != null && _tWorker.IsAlive)
                        _tWorker.Suspend();

                    // Update newest index rootlink
                    treeView1.Invoke(new Action(() =>
                    {
                        treeView1.Nodes.Clear();
                        BuildTreeView();
                        treeView1.Invalidate();
                    }));

                    // Resume crawler thread
                    _tWorker.Resume();
                }
            }
            catch { }
        }

        private void TreeViewForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_tWorker != null && _tWorker.IsAlive)
            {
                if (_tWorker.ThreadState.ToString().Contains("Suspended"))
                    _tWorker.Resume();
                _tWorker.Abort();
            }

            Application.ExitThread();
        }
    } // end class

    internal class VertexNode : TreeNode
    {
        public IVertex NVertex { get; set; }
        public VertexNode(Vertex v)
        {
            NVertex = v;
            Text = NVertex.Url;
        }
    }
}
